package pl.edu.pw.polygen.modeler.client.workspace;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import pl.edu.pw.polygen.modeler.client.graph.EdgeModel;
import pl.edu.pw.polygen.modeler.client.graph.EdgeType;
import pl.edu.pw.polygen.modeler.client.graph.GraphHandler;
import pl.edu.pw.polygen.modeler.client.graph.GraphModel;
import pl.edu.pw.polygen.modeler.client.graph.IEdgeModel;
import pl.edu.pw.polygen.modeler.client.graph.IVertexModel;
import pl.edu.pw.polygen.modeler.client.graph.VertexModel;
import pl.edu.pw.polygen.modeler.client.object.Hole;
import pl.edu.pw.polygen.modeler.client.object.IPolygenObject;
import pl.edu.pw.polygen.modeler.client.object.Segment;
import pl.edu.pw.polygen.modeler.client.object.Splain;
import pl.edu.pw.polygen.modeler.client.object.SubDomain;
import pl.edu.pw.polygen.modeler.client.object.Vertex;
import pl.edu.pw.polygen.modeler.client.object.Vertex.VertexType;
import pl.edu.pw.polygen.modeler.client.properties.Properties;
import pl.edu.pw.polygen.modeler.client.toolbox.Toolbox;

import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;

public class Editor extends Composite implements Paintable{
	
	public static final Integer eofData = 10;
	private Workspace workspace;
	private Toolbox toolbox;
	private Properties properties;
	private ApplicationConnection client = null;
	private String uidl;
	
	public Editor(){
		super();
		
		workspace = new Workspace();
		toolbox = new Toolbox(workspace);
		properties = new Properties();
		
		workspace.setSize("100%", "100%");
		workspace.setEditor(this);
		HorizontalPanel panel = new HorizontalPanel();
		
		panel.add(toolbox);
		panel.add(workspace);
		panel.add(properties);
		
		initWidget(panel);
	}
	
	public void showProperties(IPolygenObject polygenObject){
		properties.showProperty(polygenObject);
	}
	
	public void showProperties(List<IPolygenObject> polygenObjects){
		properties.showProperty(polygenObjects);
	}

	@Override
	public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
		workspace.updateFromUIDL(uidl, client);
		this.uidl = uidl.getId();
		this.client = client;
		
		if(uidl.hasVariable("boundaries")){
			boolean boundariesVisibility = uidl.getBooleanVariable("boundaries");
			workspace.setBoundariesVisibility(boundariesVisibility);
			workspace.updateAll();
		}
		
		if(uidl.hasVariable("getGraphData")){
			Long sendFlag = uidl.getLongVariable("getGraphData");
			if(sendFlag==1){
				sendGraphData();
			}
		}
		if(uidl.hasVariable("uploadFlag")){
			boolean uploadFlag = uidl.getBooleanVariable("uploadFlag");
			if(uploadFlag==true){
				workspace.clear();
				GraphHandler.getInstance(workspace.getId()).clear();
				downloadData(uidl, client);
			}
		}
	}
	
	private void downloadData(UIDL uidl, ApplicationConnection client){
		Map<Integer,Vertex> vertexMap = new HashMap<Integer,Vertex>();
		int vertexAmount = 0;
		if(uidl.hasVariable("vertexAmount")){
			vertexAmount = uidl.getIntVariable("vertexAmount");
			for(int i=0; i < vertexAmount ;i++){
				int id = 0;
				double x = 0;
				double y = 0;
				String type = "NORMAL_VERTEX";
				int boundary = 0;
				
				if(uidl.hasVariable("vertexId"+i)){
					id = uidl.getIntVariable("vertexId"+i);
				}
				if(uidl.hasVariable("vertexX"+i)){
					x = uidl.getDoubleVariable("vertexX"+i);
				}
				if(uidl.hasVariable("vertexY"+i)){
					y = uidl.getDoubleVariable("vertexY"+i);
				}
				if(uidl.hasVariable("vertexType"+i)){
					type = uidl.getStringVariable("vertexType"+i);
				}
				if(uidl.hasVariable("vertexBoundary"+i)){
					boundary = uidl.getIntVariable("vertexBoundary"+i);
				}
				VertexType vType = getVertexType(type);
				Vertex vertex = null;
				if(vType == VertexType.NORMAL_VERTEX || vType == VertexType.CONTROL_VERTEX){
					vertex = new Vertex(0, 0, workspace, getVertexType(type));
				}else if(vType == VertexType.HOLE_VERTEX){
					vertex = new Hole(0, 0, workspace);
				}else{
					vertex = new SubDomain(0, 0, workspace);
				}
				vertex.getModel().setBoundary(boundary);
				vertex.initialize();
				vertex.setModelPosition(x, y);
				vertexMap.put(id, vertex);
				if(!"CONTROL_VERTEX".equals(type))
					vertex.add();
			}
			
			for(int i=0; i<vertexAmount;i++){
				int edgesAmount = 0;
				if(uidl.hasVariable("edgesAmount"+ i)){
					edgesAmount = uidl.getIntVariable("edgesAmount"+ i);
				}
				for(int j=0; j < edgesAmount ; j++){
					int edgeB = 0;
					int edgeE = 0;
					String edgeT = "SEGMENT";
					int boundary = 0;
					int edgeCA = 0;
					int edgeCB = 0;
					double edgeStep = 0;
					if(uidl.hasVariable("edgeB"+i+"_"+j)){
						edgeB = uidl.getIntVariable("edgeB"+i+"_"+j);
					}
					if(uidl.hasVariable("edgeE"+i+"_"+j)){
						edgeE = uidl.getIntVariable("edgeE"+i+"_"+j);
					}
					if(uidl.hasVariable("edgeT"+i+"_"+j)){
						edgeT = uidl.getStringVariable("edgeT"+i+"_"+j);
					}
					if(uidl.hasVariable("edgeBoundary"+i+"_"+j)){
						boundary = uidl.getIntVariable("edgeBoundary"+i+"_"+j);
					}
					if("SPLAIN".equals(edgeT)){
						if(uidl.hasVariable("edgeCA"+i+"_"+j)){
							edgeCA = uidl.getIntVariable("edgeCA"+i+"_"+j);
						}
						if(uidl.hasVariable("edgeCB"+i+"_"+j)){
							edgeCB = uidl.getIntVariable("edgeCB"+i+"_"+j);
						}
						if(uidl.hasVariable("edgeStep"+i+"_"+j)){
							edgeStep = uidl.getDoubleVariable("edgeStep"+i+"_"+j);
						}
						Vertex vertexBegin = vertexMap.get(edgeB);
						Vertex vertexEnd = vertexMap.get(edgeE);
						Vertex controlA = vertexMap.get(edgeCA);
						Vertex controlB = vertexMap.get(edgeCB);
						
						Splain splain = new Splain(vertexBegin,vertexEnd,controlA,controlB,edgeStep,boundary,workspace);
						splain.addToCanvas();
						
						workspace.add(splain);
												
						//splain.initialize();
					}else{
						Vertex vertexBegin = vertexMap.get(edgeB);
						Vertex vertexEnd = vertexMap.get(edgeE);
						Segment segment = new Segment(vertexBegin,vertexEnd,boundary,workspace);
						segment.addToCanvas();
						workspace.add(segment);
						segment.initialize();
					}
				}
			}
		}
		workspace.updateAll();
	}
	
	private VertexType getVertexType(String type){
		if("NORMAL_VERTEX".equals(type))
			return VertexType.NORMAL_VERTEX;
		else if("CONTROL_VERTEX".equals(type))
			return VertexType.CONTROL_VERTEX;
		else if("SUBDOMAIN_VERTEX".equals(type))
			return VertexType.SUBDOMAIN_VERTEX;
		else return VertexType.HOLE_VERTEX;
	}
	
	public void sendGraphData(){
		if(client!=null){
			GraphModel graph = GraphHandler.getInstance(workspace.getId());
			List<IVertexModel> vertexes = graph.getVertexes();
			
			client.updateVariable(uidl, "vertexAmount", vertexes.size() ,false);
			for(int i=0;i<vertexes.size();i++){
				VertexModel vertexModel = (VertexModel) vertexes.get(i);
				client.updateVariable(uidl, "vertexId"+i, vertexModel.getId() ,false);
				client.updateVariable(uidl, "vertexX"+i, vertexModel.getX() ,false);
				client.updateVariable(uidl, "vertexY"+i, vertexModel.getY() ,false);
				client.updateVariable(uidl, "vertexT"+i, vertexModel.getType()+"" ,false);
				client.updateVariable(uidl, "vertexBoundary"+i, vertexModel.getBoundary() ,false);
				
				
				List<IEdgeModel> edges = vertexModel.getEdges();
				client.updateVariable(uidl, "edgesAmount"+i, edges.size() ,false);
				if(edges!=null){
					for(int j=0;j<edges.size();j++){
						EdgeModel edgeModel = (EdgeModel) edges.get(j);
						client.updateVariable(uidl, "edgeB"+i+"_"+j, edgeModel.getBegin().getId(),false);
						client.updateVariable(uidl, "edgeE"+i+"_"+j, edgeModel.getEnd().getId(),false);
						client.updateVariable(uidl, "edgeT"+i+"_"+j, edgeModel.getType()+"",false);
						client.updateVariable(uidl, "edgeBoundary"+i+"_"+j, edgeModel.getBoundary(),false);
						
						
						if(edgeModel.getType() == EdgeType.SPLAIN){
							client.updateVariable(uidl, "edgeCA"+i+"_"+j, edgeModel.getControlA().getId(),false);
							client.updateVariable(uidl, "edgeCB"+i+"_"+j, edgeModel.getControlB().getId(),false);
							client.updateVariable(uidl, "edgeStep"+i+"_"+j, edgeModel.getStep(), false);
						}
					}
				}
			}
			client.sendPendingVariableChanges();
			//client.updateVariable(uidl, "endOfData",  eofData,true);
			
		}
	}
	
}
